package cn.turboinfo.fuyang.api.gateway.web.config

import cn.turboinfo.fuyang.api.domain.common.usecase.AbstractUseCase
import cn.turboinfo.fuyang.api.gateway.web.framework.http.context.WechatPayHeaderContextHolder
import mu.KotlinLogging
import nxcloud.ext.springmvc.automapping.contract.AutoMappingContractData
import nxcloud.ext.springmvc.automapping.spi.AutoMappingContractDataConverter
import nxcloud.ext.springmvc.automapping.spi.AutoMappingRequestParameterInjector
import nxcloud.ext.springmvc.automapping.spi.AutoMappingRequestParameterTypeResolver
import nxcloud.ext.springmvc.automapping.spring.AutoMappingRequestParameterTypeBinding
import org.apache.commons.lang3.StringUtils
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.MethodParameter
import org.springframework.util.ClassUtils
import org.springframework.web.context.request.NativeWebRequest
import java.lang.reflect.Method

@Configuration
class CommonAutoMappingConfig {

    private val logger = KotlinLogging.logger {}

    /**
     * 将针对 UseCase 的自动映射处理方法名统一解析到 execute() 方法上
     */
    @Bean
    protected fun abstractUseCaseAutoMappingContractDataConverter(): AutoMappingContractDataConverter {
        return object : AutoMappingContractDataConverter {
            override fun convert(data: AutoMappingContractData): AutoMappingContractData {
                return data.copy(
                    beanMethod = "execute"
                )
            }

            override fun isSupported(data: AutoMappingContractData): Boolean {
                return AbstractUseCase::class.java.isAssignableFrom(data.beanType)
            }
        }
    }

    /**
     * 将 UseCase 的抽象入参类型解析为具体的实现类的入参类型
     */
    @Bean
    protected fun abstractUseCaseAutoMappingRequestParameterTypeResolver(): AutoMappingRequestParameterTypeResolver {
        return object : AutoMappingRequestParameterTypeResolver {
            override fun isSupported(method: Method): Boolean {
                return AbstractUseCase::class.java.isAssignableFrom(method.declaringClass)
            }

            override fun resolveParameterType(method: Method): Array<Class<*>> {
                // 需要去掉 Spring 生成的 AOP 代理类名字后缀
                val useCaseClassName =
                    StringUtils.substringBefore(method.declaringClass.canonicalName, ClassUtils.CGLIB_CLASS_SEPARATOR)
                // 固定只有一个内部类参数
                return arrayOf(Class.forName("${useCaseClassName}\$InputData"))
            }
        }
    }

    /**
     * 微信签名 自动注入
     */
    @Bean
    protected fun wechatPaySignatureAutoMappingRequestParameterInjector(
        autoMappingRequestParameterTypeBinding: AutoMappingRequestParameterTypeBinding,
    ): AutoMappingRequestParameterInjector {
        return object : AutoMappingRequestParameterInjector {
            override fun inject(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ) {
                try {
                    val field = parameterObj::class.java.getDeclaredField("wechatSignature")
                    field.isAccessible = true
                    field.set(parameterObj, WechatPayHeaderContextHolder.current().wechatSignature)
                } catch (e: NoSuchFieldException) {
                    // 忽略传递未知属性的情况
                    logger.debug { "$parameter 未要求 wechatSignature" }
                }
            }

            override fun isSupported(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ): Boolean {
                return WechatPayHeaderContextHolder.exists()
            }
        }
    }

    /**
     * 微信签名 自动注入
     */
    @Bean
    protected fun wechatPayNonceSignatureAutoMappingRequestParameterInjector(
        autoMappingRequestParameterTypeBinding: AutoMappingRequestParameterTypeBinding,
    ): AutoMappingRequestParameterInjector {
        return object : AutoMappingRequestParameterInjector {
            override fun inject(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ) {
                try {
                    val field = parameterObj::class.java.getDeclaredField("wechatNonce")
                    field.isAccessible = true
                    field.set(parameterObj, WechatPayHeaderContextHolder.current().wechatNonce)
                } catch (e: NoSuchFieldException) {
                    // 忽略传递未知属性的情况
                    logger.debug { "$parameter 未要求 wechatNonce" }
                }
            }

            override fun isSupported(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ): Boolean {
                return WechatPayHeaderContextHolder.exists()
            }
        }
    }

    /**
     * 微信时间戳 自动注入
     */
    @Bean
    protected fun wechatPayTimestampAutoMappingRequestParameterInjector(
        autoMappingRequestParameterTypeBinding: AutoMappingRequestParameterTypeBinding,
    ): AutoMappingRequestParameterInjector {
        return object : AutoMappingRequestParameterInjector {
            override fun inject(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ) {
                try {
                    val field = parameterObj::class.java.getDeclaredField("wechatTimestamp")
                    field.isAccessible = true
                    field.set(parameterObj, WechatPayHeaderContextHolder.current().wechatTimestamp)
                } catch (e: NoSuchFieldException) {
                    // 忽略传递未知属性的情况
                    logger.debug { "$parameter 未要求 wechatTimestamp" }
                }
            }

            override fun isSupported(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ): Boolean {
                return WechatPayHeaderContextHolder.exists()
            }
        }
    }

    /**
     * 微信证书串码 自动注入
     */
    @Bean
    protected fun wechatPaySerialAutoMappingRequestParameterInjector(
        autoMappingRequestParameterTypeBinding: AutoMappingRequestParameterTypeBinding,
    ): AutoMappingRequestParameterInjector {
        return object : AutoMappingRequestParameterInjector {
            override fun inject(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ) {
                try {
                    val field = parameterObj::class.java.getDeclaredField("wechatSerial")
                    field.isAccessible = true
                    field.set(parameterObj, WechatPayHeaderContextHolder.current().wechatSerial)
                } catch (e: NoSuchFieldException) {
                    // 忽略传递未知属性的情况
                    logger.debug { "$parameter 未要求 wechatSerial" }
                }
            }

            override fun isSupported(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ): Boolean {
                return WechatPayHeaderContextHolder.exists()
            }
        }
    }

    /**
     * 微信签名类型 自动注入
     */
    @Bean
    protected fun wechatPaySignatureTypeAutoMappingRequestParameterInjector(
        autoMappingRequestParameterTypeBinding: AutoMappingRequestParameterTypeBinding,
    ): AutoMappingRequestParameterInjector {
        return object : AutoMappingRequestParameterInjector {
            override fun inject(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ) {
                try {
                    val field = parameterObj::class.java.getDeclaredField("wechatSignatureType")
                    field.isAccessible = true
                    field.set(parameterObj, WechatPayHeaderContextHolder.current().wechatSignatureType)
                } catch (e: NoSuchFieldException) {
                    // 忽略传递未知属性的情况
                    logger.debug { "$parameter 未要求 wechatSignatureType" }
                }
            }

            override fun isSupported(
                parameterObj: Any,
                parameter: MethodParameter,
                resolvedParameterType: Class<*>,
                webRequest: NativeWebRequest
            ): Boolean {
                return WechatPayHeaderContextHolder.exists()
            }
        }
    }
}
